//===============================================================================
// Microsoft patterns & practices
// Guidance Explorer Offline Client
//===============================================================================
// Copyright  Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================

using System;
using System.Collections.Generic;
using System.ComponentModel;

namespace GuidanceExplorer.Model
{
    public enum SearchViewScope { Guidance, Library, Folder, View, UserViews }

    public class SearchView : View
    {
        /// <summary>
        /// Factory.
        /// </summary>
        /// <returns>A new instance of a View.</returns>
        public static new SearchView New()
        {
            return new SearchView();
        }

        /// <summary>
        /// The criteria that will be used to populate this view.
        /// </summary>
        private Criteria _criteria;

        /// <summary>
        /// The container scope for this SearchView.
        /// </summary>
        private IGuidanceItemContainer _containerScope;

        /// <summary>
        /// The scope readed from the xml file.
        /// </summary>
        private SearchViewScope _readedScope;

        /// <summary>
        /// The scope name readed form the xmlfile.
        /// </summary>
        private string _readedScopeName;

        /// <summary>
        /// Cached list of items in this search view
        /// </summary>
        private SortedList<int, GuidanceItem> cachedItemList;

        private GuidanceItemCollection _itemCollection;

        /// <summary>
        /// Default private constructor.
        /// </summary>
        private SearchView() { }

        /// <summary>
        /// SearchViews has Items.
        /// </summary>
        [Browsable(false)]
        public override bool HasItems
        {
            get { return false; }
        }

        /// <summary>
        /// Items collection can't be set.
        /// </summary>
        [Browsable(false)]
        public override bool CanSetItems
        {
            get { return false; }
        }

        /// <summary>
        /// The list of items in the view.
        /// </summary>
        [Browsable(false)]
        public override GuidanceItemCollection Items
        {
            get 
            {
                PopulateCachedItemList();
                if (_itemCollection == null)
                {
                    _itemCollection = GuidanceItemCollection.New();
                    foreach (GuidanceItem item in cachedItemList.Values)
                    {
                        _itemCollection.Add(item.Id, item);
                    }
                }

                return _itemCollection;
            }

            set { throw new Exception("Items collection can't be set."); }
        }

        /// <summary>
        /// The criteria that will be used to populate this view.
        /// </summary>
        [Browsable(false)]
        public Criteria Criteria
        {
            get { return _criteria; }
            set 
            { 
                _criteria = value;
                cachedItemList = null;
            }
        }

        /// <summary>
        /// The container scope for this SearchView.
        /// </summary>
        [Browsable(false)]
        public IGuidanceItemContainer ContainerScope
        {
            get { return _containerScope; }
            set { _containerScope = value; }
        }

        /// <summary>
        /// The scope for this search view.
        /// </summary>
        [Browsable(false)]
        public SearchViewScope Scope
        {
            get
            {
                if (_containerScope is Guidance)
                {
                    return SearchViewScope.Guidance;
                }
                else if (_containerScope is Library)
                {
                    return SearchViewScope.Library;
                }
                else if (_containerScope is Folder)
                {
                    return SearchViewScope.Folder;
                }
                else if (_containerScope is View)
                {
                    return SearchViewScope.View;
                }
                else if (_containerScope is UserViews)
                {
                    return SearchViewScope.UserViews;
                }
                throw new Exception("Invalid container type.");
            }
        }

        /// <summary>
        /// The scope readed from the xml file.
        /// </summary>
        [Browsable(false)]
        public SearchViewScope ReadedScope
        {
            get { return _readedScope; }
            set { _readedScope = value; }
        }

        /// <summary>
        /// The scope name readed form the xmlfile.
        /// </summary>
        [Browsable(false)]
        public string ReadedScopeName
        {
            get { return _readedScopeName; }
            set { _readedScopeName = value; }
        }

        public override View Clone()
        {
            SearchView newView = new SearchView();
            newView.Author = Author;
            newView.Caption = Caption;
            newView.Columns = Columns;
            newView.Container = Container;
            newView.LastUpdate = LastUpdate;
            newView.Description = Description;
            newView.Id = Guid.NewGuid().ToString();
            newView.ParentFolder = ParentFolder;
            newView.RootView = RootView;

            newView._criteria = _criteria;
            newView._containerScope = _containerScope;
            newView._readedScope = _readedScope;
            newView._readedScopeName = _readedScopeName;

            return newView;
        }

        public View CloneAsView()
        {
            View newView = View.New();
            newView.Author = Author;
            newView.Caption = Caption;
            newView.Columns = Columns;
            newView.Container = Container;
            newView.LastUpdate = LastUpdate;
            newView.Description = Description;
            newView.Id = Guid.NewGuid().ToString();
            newView.ParentFolder = ParentFolder;
            newView.RootView = RootView;

            foreach (GuidanceItem item in this)
            {
                newView.Items.Add(item.Id, item);
            }

            return newView;
        }

        #region IEnumerable Members

        public override IEnumerator<GuidanceItem> GetEnumerator()
        {
            PopulateCachedItemList();
            //Iterate through all the scoped items.
            foreach (KeyValuePair<int, GuidanceItem> pair in cachedItemList)
            {
                    yield return pair.Value;
            }
        }

        private void PopulateCachedItemList()
        {
            if (cachedItemList == null)
            {
                List<GuidanceItem> itemList = new List<GuidanceItem>(_containerScope);
                cachedItemList = new SortedList<int, GuidanceItem>();

                if (_criteria is TopSearchCriteria)
                {
                    //sort by date if we are looking for top X by date.
                    itemList.Sort(
                        delegate(GuidanceItem x, GuidanceItem y)
                        {
                            return DateTime.Compare(x.DateTime, y.DateTime) * -1;
                        }
                    );
                }
                foreach (GuidanceItem item in itemList)
                {
                    if (_criteria.Evaluate(item) && !cachedItemList.ContainsKey(item.GetHashCode()) )//Evaluate the criteria in the item.
                    {
                        //If succeed then add the item to the collection.
                        cachedItemList.Add(item.GetHashCode(), item);
                    }
                }
            }
        }

        #endregion

    }
}

